using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace Framework.Core.Collections
{
    public class ConcurrentList<T> : IList<T>
    {
        private readonly List<T> internalList = new List<T>();
        private readonly ReaderWriterLockSlim syncRoot = new ReaderWriterLockSlim();

        public IEnumerator<T> GetEnumerator()
        {
            syncRoot.EnterReadLock();
            try
            {
                return internalList.GetEnumerator();
            }
            finally
            {
                syncRoot.ExitReadLock();
            }
        }

        public void Add(T item)
        {
            syncRoot.EnterWriteLock();
            try
            {
                internalList.Add(item);
            }
            finally
            {
                syncRoot.ExitWriteLock();
            }
        }

        public void Clear()
        {
            syncRoot.EnterWriteLock();
            try
            {
                internalList.Clear();
            }
            finally
            {
                syncRoot.ExitWriteLock();
            }
        }

        public bool Contains(T item)
        {
            syncRoot.EnterReadLock();
            try
            {
                return internalList.Contains(item);
            }
            finally
            {
                syncRoot.ExitReadLock();
            }
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            syncRoot.EnterWriteLock();
            try
            {
                internalList.CopyTo(array, arrayIndex);
            }
            finally
            {
                syncRoot.ExitWriteLock();
            }
        }

        public bool Remove(T item)
        {
            syncRoot.EnterWriteLock();
            try
            {
                return internalList.Remove(item);
            }
            finally
            {
                syncRoot.ExitWriteLock();
            }
        }

        public int Count
        {
            get
            {
                syncRoot.EnterReadLock();
                try
                {
                    return internalList.Count;
                }
                finally
                {
                    syncRoot.ExitReadLock();
                }
            }
        }

        public bool IsReadOnly
        {
            get
            {
                syncRoot.EnterReadLock();
                try
                {
                    return ((IList<T>)internalList).IsReadOnly;
                }
                finally
                {
                    syncRoot.ExitReadLock();
                }
            }
        }

        public int IndexOf(T item)
        {
            syncRoot.EnterReadLock();
            try
            {
                return internalList.IndexOf(item);
            }
            finally
            {
                syncRoot.ExitReadLock();
            }
        }

        public void Insert(int index, T item)
        {
            syncRoot.EnterWriteLock();
            try
            {
                internalList.Insert(index, item);
            }
            finally
            {
                syncRoot.ExitWriteLock();
            }
        }

        public void RemoveAt(int index)
        {
            syncRoot.EnterWriteLock();
            try
            {
                internalList.RemoveAt(index);
            }
            finally
            {
                syncRoot.ExitWriteLock();
            }
        }

        public T this[int index]
        {
            get
            {
                syncRoot.EnterReadLock();
                try
                {
                    return internalList[index];
                }
                finally
                {
                    syncRoot.ExitReadLock();
                }
            }
            set
            {
                syncRoot.EnterWriteLock();
                try
                {
                    internalList[index] = value;
                }
                finally
                {
                    syncRoot.ExitWriteLock();
                }
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void AddRange(IEnumerable<T> collection)
        {
            syncRoot.EnterWriteLock();
            try
            {
                internalList.AddRange(collection);
            }
            finally
            {
                syncRoot.ExitWriteLock();
            }
        }
    }
}